export interface Info {
  title?: string;
  version?: string;
  description?: string;
  termsOfService?: string;
  contact?: Contact;
  license?: License;
}

export interface Contact {
  name?: string;
  email?: string;
  url?: string;
}

export interface License {
  name: string;
  url?: string;
}

export interface ExternalDocs {
  url: string;
  description?: string;
}

export interface Tag {
  name: string;
  description?: string;
  externalDocs?: ExternalDocs;
}

export interface Example { }

export type SchemaType = 'string' | 'number' | 'integer' | 'boolean' | 'array' | 'object' | 'file';

export interface Header extends BaseSchema {
  type: SchemaType;
}

export interface BaseParameter {
  name: string;
  in: 'body' | 'query' | 'path' | 'header' | 'formData';
  required?: boolean;
  description?: string;
}

export interface BodyParameter extends BaseParameter {
  in: 'body';
  schema?: Schema;
}

export interface QueryParameter extends BaseParameter, BaseSchema {
  in: 'query';
  type: SchemaType;
  format?: string;
  allowEmptyValue?: boolean;
  collectionFormat?: CollectionFormat;
}

export interface PathParameter extends BaseParameter {
  in: 'path';
  type: string;
  format?: string;
  required: boolean;
}

export interface HeaderParameter extends BaseParameter {
  in: 'header';
  type: string;
  format?: string;
}

export interface FormDataParameter extends BaseParameter, BaseSchema {
  in: 'formData';
  type: SchemaType;
  collectionFormat?: CollectionFormat;
}

export type CollectionFormat = 'csv' | 'ssv' | 'tsv' | 'pipes' | 'multi';

export type Parameter =
  BodyParameter |
  FormDataParameter |
  QueryParameter |
  PathParameter |
  HeaderParameter;

export interface Path {
  $ref?: string;
  get?: Operation;
  put?: Operation;
  post?: Operation;
  delete?: Operation;
  options?: Operation;
  head?: Operation;
  patch?: Operation;
  parameters?: [Parameter];
}

export interface Operation {
  responses: { [responseName: string]: Response };
  summary?: string;
  description?: string;
  externalDocs?: ExternalDocs;
  operationId?: string;
  produces?: [string];
  consumes?: [string];
  parameters?: [Parameter];
  schemes?: [string];
  deprecated?: boolean;
  security?: [Security];
  tags?: [string];
}

export interface Response {
  description: string;
  schema?: Schema;
  headers?: { [headerName: string]: Header };
  examples?: { [exampleName: string]: Example };
}

export interface BaseSchema {
  format?: string;
  title?: string;
  description?: string;
  default?: string | boolean | number | Object;
  multipleOf?: number;
  maximum?: number;
  exclusiveMaximum?: number;
  minimum?: number;
  exclusiveMinimum?: number;
  maxLength?: number;
  minLength?: number;
  pattern?: string;
  maxItems?: number;
  minItems?: number;
  uniqueItems?: boolean;
  maxProperties?: number;
  minProperties?: number;
  enum?: [string];
  type?: SchemaType;
  items?: Schema | [Schema];
}

export interface Schema extends BaseSchema {
  $ref?: string;
  allOf?: [Schema];
  additionalProperties?: boolean | { [ref: string]: string };
  properties?: { [propertyName: string]: Schema };
  discriminator?: string;
  readOnly?: boolean;
  xml?: XML;
  externalDocs?: ExternalDocs;
  example?: { [exampleName: string]: Example };
  required?: Array<string>;
  'x-apifox-folder'?: string;
  'x-apifox-refs'?: {
    [refName: string]: ApifoxRefItem;
  };
  'x-apifox'?: {
    enumDescriptions?: Record<string, string>;
  }
}

export interface ApifoxRefItem {
  $ref: string;
  'x-apifox-folder'?: string;
}

export interface XML {
  type?: string;
  namespace?: string;
  prefix?: string;
  attribute?: string;
  wrapped?: boolean;
}

export interface BaseSecurity {
  type: string;
  description?: string;
}

export interface BasicAuthenticationSecurity extends BaseSecurity { }

export interface ApiKeySecurity extends BaseSecurity {
  name: string;
  in: string;
}

export interface BaseOAuthSecuirty extends BaseSecurity {
  flow: string;
}

export interface OAuth2ImplicitSecurity extends BaseOAuthSecuirty {
  authorizationUrl: string;
}

export interface OAuth2PasswordSecurity extends BaseOAuthSecuirty {
  tokenUrl: string;
  scopes?: [OAuthScope];
}

export interface OAuth2ApplicationSecurity extends BaseOAuthSecuirty {
  tokenUrl: string;
  scopes?: [OAuthScope];
}

export interface OAuth2AccessCodeSecurity extends BaseOAuthSecuirty {
  tokenUrl: string;
  authorizationUrl: string;
  scopes?: [OAuthScope];
}

export interface OAuthScope {
  [scopeName: string]: string;
}

export type Security =
  BasicAuthenticationSecurity |
  OAuth2AccessCodeSecurity |
  OAuth2ApplicationSecurity |
  OAuth2ImplicitSecurity |
  OAuth2PasswordSecurity |
  ApiKeySecurity;

export interface ISwaggerConfig {
  swagger: string;
  info: Info;
  externalDocs?: ExternalDocs;
  host?: string;
  basePath?: string;
  schemes?: [string];
  consumes?: [string];
  produces?: [string];
  paths: { [pathName: string]: Path };
  definitions?: { [definitionsName: string]: Schema };
  parameters?: { [parameterName: string]: BodyParameter | QueryParameter };
  responses?: { [responseName: string]: Response };
  security?: [Security];
  securityDefinitions?: { [securityDefinitionName: string]: Security };
  tags?: [Tag];
}
